/*** Class Name: iFulfillAssignWorkflow
 * Author: Accenture
 * Date: 13-Jun-2011
 * Requirement/Project Name: iFulfill
 * Requirement Description: Assigns workflow to the fulfillment Items based on combination of UDAC,feature code, Region and Transaction Type.
                            If matching WF Group is found the FI is updated with 1st function and task on the workflow and also assigns ownership to the resp assignment group
 *                          If no matching WF Group is found, the fulfillment is pushed to WFException Queue.
 **/

global class iFulfillAssignWorkflow{
   
  //Called on Insert of FI.
  public static List<Fullfilment_Item__c> AssignWorkflow(list<Fullfilment_Item__c> newFItems,boolean flag)
  { 
        String productGroup=null;
        String workflowId =null;
        String stageID =null; 
        Workflow_Fulfillment_Group__c wfGroup  = null;
        Wokflow_Steps__c workflowStep = null;
        Fulfillment_Products__c fulfillProduct = null;
        list<Fulfillment_Products__c> fulfillmetProductList= new list<Fulfillment_Products__c>();
        list<Workflow_Fulfillment_Group__c> workflowfulfillmentGroupList =new list<Workflow_Fulfillment_Group__c>();         
        list<Assignment_Group_Queues__c> assignmentGroupList = new list<Assignment_Group_Queues__c>();
        List<Workflow_Stage__c> workflowStageList = new List<Workflow_Stage__c>();   
        List<Wokflow_Steps__c> workflowStepList = new List<Wokflow_Steps__c>(); 
        List<Fullfilment_Item__c> FIList  = new List<Fullfilment_Item__c>();
        List<Fullfilment_Item__c> changeRequestFIList = new List<Fullfilment_Item__c>();

        boolean FIRecordOkay = false; 
        Set<String> caseOwnerSet = new Set<String>();
        Set<String> groupSet= new Set<String>();
        Map<ID,String> caseOwnerMap = new Map<ID,String>();
        List<GroupMember> groupMemberList = new List<GroupMember>();


        /*Stores the 'Active' Fulfillment Product's Product UDAC Code,Feature into map mFP */
        Map<string,Fulfillment_Products__c> mFP= new Map<string,Fulfillment_Products__c>(); 
        
        /*Stores the 'Active' Workflow Fulfillment Group's product Group into the map mWFG */
        Map<string,List<Workflow_Fulfillment_Group__c>> mWFG= new Map<string,List<Workflow_Fulfillment_Group__c>>(); 
        
        /*Stores the 'Active' Workflow's 1st Function id into the map mWF */
        Map<ID,ID> mWF= new Map<ID,ID>(); 
        
        /*Stores the 'Active' Workflow Function's 1st Task into map mWT */
        Map<ID,Wokflow_Steps__c> mWT= new Map<ID,Wokflow_Steps__c>();
        
        /*Stores the  all the Fulfillment Assignment Group*/
        Map<ID,ID> mAG= new Map<ID,ID>();
        
                  
         fulfillmetProductList= [select Product_UDAC_Code__c,Feature__c,Fulfillment_Product_Group__c,Feature_Description__c,Package__c,Product_Descritpion__c,Product_Family__c from Fulfillment_Products__c where Status__c = 'Active'];         
         for(Fulfillment_Products__c FP :fulfillmetProductList){
             mFP.put(FP.Product_UDAC_Code__c+FP.Feature__c,FP);         
         } 
          
         workflowfulfillmentGroupList =[select Workflow__c,Workflow__r.Version__c,Product_Group__c,Order_Types__c,Advertiser_Region__c from Workflow_Fulfillment_Group__c where Workflow__r.Status__c = 'Active' and status__c ='Active'];                    
         for(Workflow_Fulfillment_Group__c WFG :workflowfulfillmentGroupList){
             if(mWFG.size()>0 && mWFG.containsKey(WFG.Product_Group__c)){
                mWFG.get(WFG.Product_Group__c).add(WFG);
             }else{
                mWFG.put(WFG.Product_Group__c,new List<Workflow_Fulfillment_Group__c>{WFG});        
             } 
         } 
         
         // retrieves workflow's '1st' function                                            
         workflowStageList=[select id,Workflow_Code__c,sequence__C from Workflow_Stage__c  where sequence__C=1  and Workflow_Code__r.Status__c = 'Active' order by sequence__C ];
         for(Workflow_Stage__c WS :workflowStageList){
             mWF.put(WS.Workflow_Code__c,WS.id);        
         }                         
         // retrieves workflow's '1st' tasks     
         workflowStepList =[select id,Wokflow_Stage_Name__c,Default_Group__c,sequence__C from Wokflow_Steps__c  where sequence__C=1 and Wokflow_Stage_Name__c in :workflowStageList];         
         for(Wokflow_Steps__c WT :workflowStepList){
             mWT.put(WT.Wokflow_Stage_Name__c,WT);        
         } 
         //retrieves assignment groups for the workflows        
         assignmentGroupList = [select QueueId__c,Assignment_Group_Name__c from Assignment_Group_Queues__c where Assignment_Group_Name__r.type__c = 'Fulfillment'];                 
         for(Assignment_Group_Queues__c AG:assignmentGroupList){
             mAG.put(AG.Assignment_Group_Name__c,AG.QueueId__c);             
         }                           
        QueueSobject queueData =[ Select q.QueueId from QueueSobject q where q.Queue.Name = :IfullfillTextConstant.WORKFLOWEXCEPTIONQUEUE Limit 1];           
        
          // IF the Transaction type is 'Change Request ' or 'Escalation' than create Map -to assign the case owner to FI Owner.
         for(Fullfilment_Item__c FI :newFItems){
           if(FI.Related_Case_Id__c !=null && FI.OwnerId__c !=null 
                 && FI.Transaction_Type__c !=null 
                    && (FI.Transaction_Type__c.equals(IfullfillTextConstant.FI_TRANSACTION_TYPE_CHANGE_REQUEST)
                          || FI.Transaction_Type__c.equals(IfullfillTextConstant.FI_TRANSACTION_TYPE_ESCALATION))){
                              
                 caseOwnerMap.put(FI.Related_Case_Id__c,FI.OwnerId__c);
                 caseOwnerSet.add(FI.OwnerId__c);
                
           } 
        }
         if(!caseOwnerSet.isEmpty()){
           //if the queue member is  the case owner, fetch the queue and queue menbers .
           groupMemberList = [select id, GroupId,UserOrGroupId from GroupMember where UserOrGroupId in :caseOwnerSet];    
         }   
        for(GroupMember gm:groupMemberList){
            groupSet.add(gm.UserOrGroupId+'-'+gm.GroupId);
        }          
      /* Iterating all Fulfillment items */      
      for(Fullfilment_Item__c FI :newFItems)
          {          
            try
            {   
              /*If the selected Fuflfillment UDAC, Feature Code is matches with the Fulfillment Products map mFP. */  
              if(mFP.size()>0 && mFP.containsKey(FI.UDAC__c+FI.Feature_Code__c) )
              {
                  fulfillProduct =mFP.get(FI.UDAC__c+FI.Feature_Code__c);
                  productGroup = fulfillProduct.Fulfillment_Product_Group__c;
                                    
                  /*If the Fulfillment Product's product group is matches with the Workflow Fulfillment Group product */                  
                  if(productGroup!=null && mWFG.size()>0 && mWFG.containsKey(productGroup)){                   
                      for(Workflow_Fulfillment_Group__c w1 : mWFG.get(productGroup))
                      {
                        System.debug('productGroup '+productGroup);
                        system.debug('FI.Transaction_Type__c'+FI.Transaction_Type__c+'w1.Order_Types__c'+w1.Order_Types__c);
                        system.debug('w1.Advertiser_Region__c'+w1.Advertiser_Region__c+'FI.Region__c'+FI.Region__c);
                      
                        /*If the selected Fulfillment Order type,Transaction type,Region matches with the Workflow Fulfillment Group map */                        
                        if(w1.Order_Types__c !=null && w1.Order_Types__c.equalsIgnoreCase(FI.Transaction_Type__c)
                                && w1.Advertiser_Region__c !=null && w1.Advertiser_Region__c.equalsIgnoreCase(FI.Region__c))
                         {                          
                            workflowId =w1.Workflow__c;
                            wfGroup = w1;
                            System.debug('Workflow Id '+ workflowId);                              
                            break;  //matching workflow found!!!
                          }
                     }                     
                     /*Checks if 'Active' Workflow has the Function or not */
                     if(workflowId !=null  && mWF.size()>0 && mWF.containsKey(workflowId)) 
                     {               
                         stageID= mWF.get(workflowId);
                         /*Check the Workflow Function has the Task assiocated or not */                         
                         if(mWT.size()>0 && mWT.containsKey(stageID)){
                             workflowStep=mWT.get(stageID);                              
                            /*Checks if the Task's Assignment Group matches with the Assignment Grop Queue*/                             
                            if(mAG.size()>0 && mAG.containsKey(workflowStep.Default_Group__c)){                                
                               FIRecordOkay = true; //all criteria for workflow assignment are met
                            }                               
                         }                               
                      } 
                   }                                           
               }                                
               /*Update FI if all criteria are met else push to Exception Queue*/ 
               if(FIRecordOkay)
                {   
                               System.debug('Fulfillment ID' +FI.ID);
                               System.debug('fulfillProduct Details '+fulfillProduct);                               
                               FI.Fulfillment_Product_Group__c=fulfillProduct.Fulfillment_Product_Group__c;
                               FI.Feature__c= fulfillProduct.Feature_Description__c;
                               FI.Package_Multi_feature_Product__c= fulfillProduct.Package__c;
                               FI.UDAC_Description__c= fulfillProduct.Product_Descritpion__c;
                               FI.Product_Family__c= fulfillProduct.Product_Family__c; 
                               FI.Workflow_Code__c =wfGroup.Workflow__c;
                               FI.Workflow_Version__c =wfGroup.Workflow__r.Version__c;
                               FI.Workflow_Start_Date__c= System.now();
                               FI.Status__c = IfullfillTextConstant.FI_WORKFLOW_OPEN_STATUS;
                               FI.Current_Stage__c =stageID;
                               FI.Current_Stage_Start_Date__c=System.now();
                               FI.Current_Step__c =workflowStep.ID; 
                               FI.Current_Step_Start_Date__c =System.now();
                               // If the transaction type 'change Request' or 'Escalation' assign the case owner to FI owner.
                               if((FI.Transaction_Type__c.equals(IfullfillTextConstant.FI_TRANSACTION_TYPE_CHANGE_REQUEST))
                                  ||(FI.Transaction_Type__c.equals(IfullfillTextConstant.FI_TRANSACTION_TYPE_ESCALATION))){
                                   
                                  ID caseownerid=iFulfillAssignWorkflow.assignCaseOwnerToFIOnwer(FI,mAG.get(workflowStep.Default_Group__c),groupSet,caseOwnerMap);
                                  FI.ownerid=caseownerid;
                                }else{
                                   FI.ownerid=mAG.get(workflowStep.Default_Group__c);
                                }   
                               
                               FIList.add(FI);                             
                }
                else{
                   System.debug('No Worklfow Found .Enter into the Exception Queue loop');
                   FI.ownerid=queueData.QueueId;                   
                } 
                productGroup = null; 
                workflowId=null;
                workflowStep= null;
                stageID = null; 
                FIRecordOkay =false;
              }              
              catch(Exception e)
              {                
                GeneralConstants.mailAnyExceptionToMe('iFulfillAssignWorkflow','AssignWorkflow',e);
              }
         } 
         
        Map <ID ,Fullfilment_Item__c > fiMap  = new Map<ID,Fullfilment_Item__c>();
        for( Fullfilment_Item__c obj: FIList)
        {
            fiMap.put(obj.id, obj);
        }
           
        IFullfilmentItemRoundRobin.executeRoundRobin(FIList,  true,false ,fiMap   ,true);   
        return FIList;
     }
     /*** Assign the case owner to FI owner based on the 
      *   if the case owner is part of the assignement group than set case owner to FI owner 
      *   else default assignemnt group is FI Owner.
      ***/
    static ID assignCaseOwnerToFIOnwer(Fullfilment_Item__c FI,ID assignmentGroupid,Set<String> groupSet,Map<ID,String> caseOwnerMap){
        ID FIOwner;
        if(caseOwnerMap.containsKey(FI.Related_Case_Id__c)){
          String caseOwner=caseOwnerMap.get(FI.Related_Case_Id__c);
          System.debug('Case Owner Data and AssignmentGroupid'+caseOwner+'-'+assignmentGroupid);
          if(caseOwner!=null && groupSet.contains(caseOwner+'-'+assignmentGroupid)){
              FIOwner=caseOwner;
          }else{
              System.debug('Case Owner is not part of appropriate Queue');
              FIOwner=assignmentGroupid;
          }       
        }else{
               System.debug('There is no Case assigned to FI');
               FIOwner=assignmentGroupid;
        }
        System.debug('final FIOwner'+FIOwner);
       return FIOwner;
    }
    /*
    * This Method is creating 'open' Status TaskHistory Record for the Change Request Fulfillment Items.
    */
    public static void createOpenStepHistoryForChangeRequest(list<Fullfilment_Item__c> FI){
    
            Map<ID,String> createdByUserNameMap = new Map<ID,String>();  
            list<Fulfillment_Step_History__c> FSHlist = new List<Fulfillment_Step_History__c>();       
           
           /* Add all Fulfillment id,created user into Map. Need to write explicit query to access createdby name*/
           
           for(Fullfilment_Item__c fItem:[Select id,CreatedBy.name from Fullfilment_Item__c where id in :FI]){           
               createdByUserNameMap.put(fItem.id,fItem.CreatedBy.name);                             
            } 
           for(Fullfilment_Item__c fItem :FI){
                 Fulfillment_Step_History__c FSH = new Fulfillment_Step_History__c();                 
                 FSH.Stage__c                   = fItem.Current_Function_Name__c;   
                 FSH.Step__c                    = fItem.Current_Task_Name__c;
                 FSH.Target_Days_Function__c    = fItem.Current_Stage_Target_days__c;               
                 FSH.Target_Days_Task__c        = fItem.Current_Step_Target_days__c;                  
                 FSH.Fullfilment_Item__c        = fItem.id;
                 FSH.ownerId                    = fItem.createdById;
                 FSH.Status__c                  = 'Open'; 
                 FSH.Task_Start_Date__c         = System.now();
                 FSH.Task_End_Date__c           = System.now(); 
                 FSH.Workflow_Id__c             = fItem.Workflow_Name__c;
                 FSH.Sequence__c                = fItem.Function_Sequence__c;                 
                  /*To assign createdBy user of Fulfillment Item to Owner__c field */
                 if(createdByUserNameMap.containsKey(fItem.ID)){
                     FSH.Owner__c     = createdByUserNameMap.get(fItem.ID);
                     System.debug('fItem.Owner_Reporting__c'+fItem.Owner_Reporting__c+'FSH.Owner__c'+FSH.Owner__c);
                 }   
                 FSH.Task_Sequence__c           = fItem.Task_Sequence__c;
                 FSH.Dashboard_Function__c      = fItem.Task_Dashboard_Function__c;
                 FSH.Rework_Function__c         = fItem.Current_Function_Name__c;      
                 FSH.Rework_Task__c             = fItem.Current_Task_Name__c ;
                 FSH.Rework_Function_Sequence__c= fItem.Function_Sequence__c; 
                 FSH.Rework_Task_Sequence__c    = fItem.Task_Sequence__c;
                 FSH.type__c                    = IfullfillTextConstant.FI_NEW;  
                 FSHlist.add(FSH);
                 }
                 try{                                       
                     insert FSHlist;
                 }   
                 catch(dmlException insertException){
                             GeneralConstants.mailAnyExceptionToMe('ifulfillAssignWorkflow','createOpenStepHistoryForChangeRequest',insertException);
                 }
           }
     
 }